package com.zhiche.lisa.bms.service.driver.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.zhiche.lisa.bms.constant.DWaybillFeeEnum;
import com.zhiche.lisa.bms.dao.model.driver.*;
import com.zhiche.lisa.bms.service.driver.*;
import com.zhiche.lisa.core.supports.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * Created by zhaoguixin on 2018/9/10.
 */
@Service
@Slf4j
public class CalcDriverCostImpl implements ICalcDriverCost {

    @Autowired
    private IVehicleClassifyService vehicleClassifyService;

    @Autowired
    private IBaseCvTankvolumeService baseCvTankvolumeService;

    @Autowired
    private IPriceconfOcService priceconfOcService;

    @Autowired
    private IRouteService routeService;

    @Autowired
    private IPriceconfMileService priceconfMileService;

    @Autowired
    private IPriceconfFreightService priceconfFreightService;

    @Autowired
    private IFuelPriceEffectiveService fuelPriceEffectiveService;

    @Autowired
    private IFuelTypeService fuelTypeService;

    @Autowired
    private DCarAllowanceService dCarAllowanceService;

    private static final Integer COMMON_INT = 5;

    /**
     * 人送获取计算价格 - 第一桶油
     *
     * @param vehicleClassifyId 标准车型ID
     * @param oProvince         起运省
     * @param oTag              起运区域
     * @param dProvice          目的市
     * @param dTag              目的区域
     * @param extraCost         附加费
     * @param effectDate        有效时间
     * @return
     * @throws Exception
     */
    @Override
    public Map<Integer, Object> getWaybillCostByCalc(String vehicleClassifyId, String oProvince, String oTag, String
            dProvice, String dTag, BigDecimal extraCost, Date effectDate) throws Exception {

        if (null == vehicleClassifyId && "0" == vehicleClassifyId) {
            log.error("CalcDriverCostImpl.getWaybillCostByCalc param vehicleClassifyId must not be null");
            throw new IllegalArgumentException("车型分类编码不能为空");
        }

        if (StringUtils.isBlank(oProvince)) {
            log.error("CalcDriverCostImpl.getWaybillCostByCalc param oProvince must not be null");
            throw new IllegalArgumentException("起始地省份不能为空");
        }

        if (StringUtils.isBlank(oTag)) {
            log.error("CalcDriverCostImpl.getWaybillCostByCalc param oTag must not be null");
            throw new IllegalArgumentException("起始地城市不能为空");
        }

        if (StringUtils.isBlank(dProvice)) {
            log.error("CalcDriverCostImpl.getWaybillCostByCalc param dProvice must not be null");
            throw new IllegalArgumentException("目的地省份不能为空");
        }

        if (StringUtils.isBlank(dTag)) {
            log.error("CalcDriverCostImpl.getWaybillCostByCalc param dTag must not be null");
            throw new IllegalArgumentException("目的地城市不能为空");
        }

        /**
         * 查询车型分类
         */
        Wrapper ewVehicel = new EntityWrapper();
        ewVehicel.eq("vehicle_classify_id", vehicleClassifyId);
        VehicleClassify dVehicleClassify = vehicleClassifyService.selectOne(ewVehicel);
        if (null == dVehicleClassify) {
            log.error("CalcDriverCostImpl.getWaybillCostByCalc dVehicleClassify must not be null");
            throw new BaseException("车型分类不能为空");
        }

        /**
         * 查询油箱容积
         */
        Wrapper ewCvTank = new EntityWrapper();
        ewCvTank.eq("cv_type_id", vehicleClassifyId);
        BaseCvTankvolume scBaseCvTankvolume = baseCvTankvolumeService.selectOne(ewCvTank);
        if (null == scBaseCvTankvolume) {
            log.error("CalcDriverCostImpl.getWaybillCostByCalc scBaseCvTankvolume must not be null");
            throw new BaseException("油箱容积不能为空");
        }

        /**
         * 查询车型油耗
         */
        Wrapper ewPriceconfOc = new EntityWrapper();
        ewPriceconfOc.eq("vehicle_type_id", dVehicleClassify.getId());
        // ewPriceconfOc.le("effective_date", new Date());
        // ewPriceconfOc.isNull("invalid_date");
        getCommonWrapper(ewPriceconfOc, "effective_date", "invalid_date", effectDate);
        PriceconfOc scPriceconfOc = priceconfOcService.selectOne(ewPriceconfOc);
        if (null == scPriceconfOc) {
            log.error("CalcDriverCostImpl.getWaybillCostByCalc scPriceconfOcs must not be null");
            throw new BaseException("车型油耗不能为空");
        }

        /**
         * 匹配线路
         */
        Wrapper ewRoute = new EntityWrapper();
        ewRoute.eq("o_province", oProvince);
        ewRoute.eq("o_tag", oTag);
        ewRoute.eq("d_province", dProvice);
        ewRoute.eq("d_tag", dTag);
        Route route = routeService.selectOne(ewRoute);
        if (null == route) {
            log.info("CalcDriverCostImpl.getWaybillCostByCalc has no match route");
            throw new BaseException("没有匹配的线路");
        }

        /**
         * 查询线路生效里程
         */
        Wrapper ewPriceconfMile = new EntityWrapper();
        ewPriceconfMile.eq("route_id", route.getId());
        // ewPriceconfMile.le("effective_date", new Date());
        // ewPriceconfMile.isNull("invalid_date");
        getCommonWrapper(ewPriceconfMile, "effective_date", "invalid_date", effectDate);
        PriceconfMile scPriceconfMile = priceconfMileService.selectOne(ewPriceconfMile);
        if (null == scPriceconfMile) {
            log.error("CalcDriverCostImpl.getWaybillCostByCalc scPriceconfMile must not be null");
            throw new BaseException("线路里程变更不能为空");
        }
        /**
         * 查询线路生效每公里劳务价
         */
        Wrapper ewPriceconfFreight = new EntityWrapper();
        ewPriceconfFreight.eq("route_id", route.getId());
        // ewPriceconfFreight.le("effective_date", new Date());
        // ewPriceconfFreight.isNull("invalid_date");
        getCommonWrapper(ewPriceconfFreight, "effective_date", "invalid_date", effectDate);
        PriceconfFreight scPriceconfFreight = priceconfFreightService.selectOne(ewPriceconfFreight);
        if (null == scPriceconfFreight) {
            log.error("CalcDriverCostImpl.getWaybillCostByCalc error matchRoute is null");
            throw new BaseException("线路价格变更不能为空");
        }

        //查询市场油价
        FuelPriceEffective fuelPriceEffective = this.selectCurrentOilPrice(dVehicleClassify.getFuelTypeId(), effectDate);
        if (null == fuelPriceEffective) {
            log.error("CalcDriverCostImpl.getWaybillCostByCalc fuelPriceEffective must not be null");
            throw new BaseException("当前市场价不能为空");
        }
        //单公里补贴
        BigDecimal kmSubsidies = BigDecimal.ZERO;
        //订单补贴
        BigDecimal orderSubsidies = BigDecimal.ZERO;

        //按车型补贴费用
        Wrapper<DCarAllowance> vcTypeWrapper=new EntityWrapper<>();
        vcTypeWrapper.eq("vc_type_id",vehicleClassifyId);
        getCommonWrapper(vcTypeWrapper, "effective_date", "invalid_date", effectDate);
        DCarAllowance vcType = dCarAllowanceService.selectOne(vcTypeWrapper);
        if(Objects.nonNull(vcType)){
            kmSubsidies=vcType.getSubsidies();
        }else{
            Calendar cal = Calendar.getInstance();
            int month = cal.get(Calendar.MONTH) + 1;
            //按地区加减补贴费用
            Wrapper<DCarAllowance> locationWrapper=new EntityWrapper<>();
            locationWrapper.eq("end_province",dProvice);
            getCommonWrapper(locationWrapper, "effective_date", "invalid_date", effectDate);
            DCarAllowance location = dCarAllowanceService.selectOne(locationWrapper);
            if (Objects.nonNull(location)) {
                if (StringUtils.isBlank(location.getExcludeCity()) || !location.getExcludeCity().contains(dTag.split("-")[0])) {
                    if (location.getType() == 3 && month >= 10 || month <= 3) {
                        orderSubsidies = location.getSubsidies();
                    } else {
                        orderSubsidies = location.getSubsidies();
                    }
                }
            }
        }

        Integer fuelTypeId = dVehicleClassify.getFuelTypeId(); // 油品id
        FuelType dFuelType = fuelTypeService.selectById(fuelTypeId);
        String fuleName = dFuelType.getFuelName(); // 油品

        //里程
        BigDecimal distance = scPriceconfMile.getCurrentValue();

        //油箱容积
        BigDecimal tankVolume = scBaseCvTankvolume.getTankVolume();

        //车型油耗
        BigDecimal currentValue = scPriceconfOc.getCurrentValue();

        //劳务费单价
        BigDecimal laborCosts = scPriceconfFreight.getCurrentValue().add(kmSubsidies);


        //单趟所需油量y
        //BigDecimal totalOil = currentValue.multiply(distance).divide(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
        // BigDecimal totalOil = currentValue.multiply(distance).divide(BigDecimal.valueOf(100).setScale(2, RoundingMode.DOWN));
        BigDecimal totalOil = currentValue.multiply(distance).divide(BigDecimal.valueOf(100).setScale(COMMON_INT, BigDecimal.ROUND_HALF_UP));

        //油箱最高加油量z
        //BigDecimal maxOil = tankVolume.multiply(BigDecimal.valueOf(0.85)).setScale(2, RoundingMode.HALF_UP);
        // BigDecimal maxOil = tankVolume.multiply(BigDecimal.valueOf(0.85)).setScale(2, RoundingMode.DOWN);
        BigDecimal maxOil = tankVolume.multiply(BigDecimal.valueOf(0.85));

        //第一箱油量
        BigDecimal firstBucketOil = null;

        //剩余油量
        BigDecimal remainOil = null;

        //单趟所需油量>=油箱最高加油量,第一箱油为油箱最高加油量z,剩余油量为单趟所需油量-油箱最高加油量 x-z
        if (totalOil.intValue() >= maxOil.intValue()) {
            firstBucketOil = maxOil;
            remainOil = totalOil.subtract(maxOil);
        }
        //单趟所需油量<油箱最高加油量,第一箱油为单趟所需油量y,油箱剩余油量为x-y即为0
        if (totalOil.intValue() < maxOil.intValue()) {
            firstBucketOil = totalOil;
            remainOil = totalOil.subtract(totalOil);
        }
        // 第一桶油量向下取整数
        firstBucketOil = firstBucketOil.setScale(0, BigDecimal.ROUND_DOWN);

        // 单公里油价  百公里油耗 /100 * 油价
        // BigDecimal priceOilPerKm = scPriceconfOc.getCurrentValue().divide(BigDecimal.valueOf(100)).multiply(fuelPriceEffective.getMarketPrice()).setScale(2, RoundingMode.HALF_UP);
        // BigDecimal priceOilPerKm = scPriceconfOc.getCurrentValue().divide(BigDecimal.valueOf(100)).multiply(fuelPriceEffective.getMarketPrice()).setScale(2, RoundingMode.DOWN);
        BigDecimal priceOilPerKm = scPriceconfOc.getCurrentValue().divide(BigDecimal.valueOf(100)).multiply(fuelPriceEffective.getMarketPrice()).setScale(COMMON_INT, BigDecimal.ROUND_HALF_UP);

        // 总劳务费 = 劳务费单价 * 里程
        // BigDecimal totalLaborCosts = laborCosts.multiply(distance).setScale(2, RoundingMode.HALF_UP);
        BigDecimal totalLaborCosts = laborCosts.multiply(distance);

        // 总油费 =  单公里油价 * 里程
        // BigDecimal totalOilFee = priceOilPerKm.multiply(distance).setScale(2, RoundingMode.HALF_UP);
        // BigDecimal totalOilFee = scPriceconfOc.getCurrentValue().divide(BigDecimal.valueOf(100)).multiply(fuelPriceEffective.getMarketPrice()).multiply(distance).setScale(2, RoundingMode.HALF_UP);
        BigDecimal totalOilFee = scPriceconfOc.getCurrentValue().divide(BigDecimal.valueOf(100)).multiply(fuelPriceEffective.getMarketPrice()).multiply(distance).setScale(COMMON_INT, BigDecimal.ROUND_HALF_UP);

        // 总油量
        // BigDecimal totalFuelConsumption = scPriceconfOc.getCurrentValue().divide(BigDecimal.valueOf(100)).multiply(distance).setScale(2, RoundingMode.HALF_UP);
        BigDecimal totalFuelConsumption = scPriceconfOc.getCurrentValue().divide(BigDecimal.valueOf(100)).multiply(distance).setScale(COMMON_INT, BigDecimal.ROUND_HALF_UP);

        // 第一桶油费 = 市场价 * 第一桶油量
        // BigDecimal firstBucketFee = firstBucketOil.multiply(fuelPriceEffective.getMarketPrice()).setScale(2, RoundingMode.HALF_UP);
        // BigDecimal firstBucketFee = remainOil.compareTo(new BigDecimal("0.00")) == 0 ? totalOilFee : firstBucketOil.multiply(fuelPriceEffective.getMarketPrice()).setScale(2, BigDecimal.ROUND_HALF_UP);
        BigDecimal firstBucketFee = firstBucketOil.multiply(fuelPriceEffective.getMarketPrice()).setScale(2, BigDecimal.ROUND_HALF_UP);

        // 剩余油费（充值油费） = 总油费 - 第一桶油费
        BigDecimal remainingOilFee = totalOilFee.subtract(firstBucketFee);

        //总运价 =  总劳务费 + 总油费 + 附加费；
        if (null == extraCost) {
            extraCost = new BigDecimal(0);
        }
        BigDecimal totalFreight = BigDecimal.ZERO;
        if (String.valueOf(orderSubsidies).contains("-")){
            String substring = String.valueOf(orderSubsidies).substring(1);
            BigDecimal bigDecimal = new BigDecimal(substring);
            totalFreight =totalLaborCosts.add(totalOilFee).add(extraCost).subtract(bigDecimal).setScale(2, BigDecimal.ROUND_HALF_UP);
            totalLaborCosts=totalLaborCosts.subtract(bigDecimal);
        }else {
            totalFreight=totalLaborCosts.add(totalOilFee).add(extraCost).add(orderSubsidies).setScale(2, BigDecimal.ROUND_HALF_UP);
            totalLaborCosts=totalLaborCosts.add(orderSubsidies);
        }
        Map<Integer, Object> fees = new HashedMap();
        fees.put(DWaybillFeeEnum.LABOR_COSTS.getValue(), totalLaborCosts);//运费(服务费)
        fees.put(DWaybillFeeEnum.REMAINING_OIL_FEE.getValue(), remainingOilFee);//油卡充值金额
        fees.put(DWaybillFeeEnum.MARKET_OIL_PRICE.getValue(), fuelPriceEffective.getMarketPrice());//油价
        fees.put(DWaybillFeeEnum.TOTAL_OIL_COST.getValue(), totalOilFee.setScale(2, BigDecimal.ROUND_HALF_UP));//总油费
        fees.put(DWaybillFeeEnum.TOTAL_SHIPPING_COST.getValue(), totalFreight);//总运费
        fees.put(DWaybillFeeEnum.SHIP_DISTANCE.getValue(), distance);//公里数   =1 后加
        fees.put(DWaybillFeeEnum.PRICE_PER_KM.getValue(), laborCosts);//单公里运价   =2 后加
        fees.put(DWaybillFeeEnum.FIRST_BUCKET_OIL_FEE.getValue(), firstBucketFee.setScale(2, BigDecimal.ROUND_HALF_UP));//第一桶油费 = 3 后加
        fees.put(DWaybillFeeEnum.PRICE_OIL_PER_KM.getValue(), priceOilPerKm);//单公里油价 = 4 后加
        fees.put(DWaybillFeeEnum.FIRST_BUCKET_OIL.getValue(), firstBucketOil);//第一桶油量 = 5 2017-06-06 11:22:55  ligl
        fees.put(DWaybillFeeEnum.OIL_CONSUMPTION.getValue(), currentValue);//车型油耗 = 6 2017-06-06 11:22:55  ligl
        fees.put(DWaybillFeeEnum.REMAIN_OIL.getValue(), remainOil);//剩余油量 = 7 2017-06-06 11:22:55  ligl
        fees.put(DWaybillFeeEnum.TANKVOLUME.getValue(), tankVolume);//车型容积 = 8 2017-06-06 11:22:55  ligl
        fees.put(DWaybillFeeEnum.FUEL_TYPE.getValue(), fuleName);//油品 = 9 2017-06-06 11:22:55  ligl
        fees.put(DWaybillFeeEnum.TOTAL_FUEL_CONSUMPTION.getValue(), totalFuelConsumption);//总油量 = 10 2017-07-05 17:45:50  ligl

        return fees;

           /* 判断条件	第一箱油量	剩余油量
            Y≥Z         	Z	        X-Z
            Y<Z         	Y	        X-Y
            备注：
            X:单趟所需油量=油耗*加油里程/100
            Y:单趟所需油量
            Z:油箱最高加油量=油箱容积*0.85
            注：原来计算方式种，Y=X*0.85，修改后X与Y相等，即X=Y
            */
    }

    /**
     * 计算价格
     * 返回 第一桶油 距离  价格 运费等
     *
     * @param vehicleClassifyId 标准车型ID
     * @param oProvince         起运省
     * @param oTag              起运区域
     * @param dProvice          目的市
     * @param dTag              目的区域
     * @param extraCost         附加费
     * @param effectDate        有效时间
     * @return
     * @throws Exception
     */
    @Override
    public Map<Integer, Object> getPriceMapForSendByDriver(String vehicleClassifyId, String oProvince, String oTag, String dProvice, String dTag, BigDecimal extraCost, Date effectDate) {
        if (null == vehicleClassifyId && "0" == vehicleClassifyId) {
            return null;
        }
        if (StringUtils.isBlank(oProvince) || StringUtils.isBlank(oTag) || StringUtils.isBlank(dProvice) || StringUtils.isBlank(dTag)) {
            return null;
        }

        /**
         * 查询车型分类
         */
        Wrapper ewVehicel = new EntityWrapper();
        ewVehicel.eq("vehicle_classify_id", vehicleClassifyId);
        VehicleClassify dVehicleClassify = vehicleClassifyService.selectOne(ewVehicel);
        if (null == dVehicleClassify) {
            return null;
        }

        /**
         * 查询油箱容积
         */
        Wrapper ewCvTank = new EntityWrapper();
        ewCvTank.eq("cv_type_id", vehicleClassifyId);
        BaseCvTankvolume scBaseCvTankvolume = baseCvTankvolumeService.selectOne(ewCvTank);
        if (null == scBaseCvTankvolume) {
            return null;
        }

        /**
         * 查询车型油耗
         */
        Wrapper ewPriceconfOc = new EntityWrapper();
        ewPriceconfOc.eq("vehicle_type_id", dVehicleClassify.getId());
        // ewPriceconfOc.le("effective_date", new Date());
        // ewPriceconfOc.isNull("invalid_date");
        getCommonWrapper(ewPriceconfOc, "effective_date", "invalid_date", effectDate);
        PriceconfOc scPriceconfOc = priceconfOcService.selectOne(ewPriceconfOc);
        if (null == scPriceconfOc) {
            return null;
        }

        /**
         * 匹配线路
         */
        Wrapper ewRoute = new EntityWrapper();
        ewRoute.eq("o_province", oProvince);
        ewRoute.eq("o_tag", oTag);
        ewRoute.eq("d_province", dProvice);
        ewRoute.eq("d_tag", dTag);
        Route route = routeService.selectOne(ewRoute);
        if (null == route) {
            return null;
        }

        /**
         * 查询线路生效里程
         */
        Wrapper ewPriceconfMile = new EntityWrapper();
        ewPriceconfMile.eq("route_id", route.getId());
        getCommonWrapper(ewPriceconfMile, "effective_date", "invalid_date", effectDate);
        PriceconfMile scPriceconfMile = priceconfMileService.selectOne(ewPriceconfMile);
        if (null == scPriceconfMile) {
            return null;
        }
        /**
         * 查询线路生效每公里劳务价
         */
        Wrapper ewPriceconfFreight = new EntityWrapper();
        ewPriceconfFreight.eq("route_id", route.getId());
        getCommonWrapper(ewPriceconfFreight, "effective_date", "invalid_date", effectDate);
        PriceconfFreight scPriceconfFreight = priceconfFreightService.selectOne(ewPriceconfFreight);
        if (null == scPriceconfFreight) {
            return null;
        }

        //查询市场油价
        FuelPriceEffective fuelPriceEffective = this.selectCurrentOilPrice(dVehicleClassify.getFuelTypeId(), effectDate);
        if (null == fuelPriceEffective) {
            return null;
        }
        //补贴
        BigDecimal subsidy= BigDecimal.ZERO;
        //单公里补贴
        BigDecimal kmSubsidies = BigDecimal.ZERO;
        //订单补贴
        BigDecimal orderSubsidies = BigDecimal.ZERO;

        //按车型补贴费用
        Wrapper<DCarAllowance> vcTypeWrapper=new EntityWrapper<>();
        vcTypeWrapper.eq("vc_type_id",vehicleClassifyId);
        getCommonWrapper(vcTypeWrapper, "effective_date", "invalid_date", effectDate);
        DCarAllowance vcType = dCarAllowanceService.selectOne(vcTypeWrapper);
        if(Objects.nonNull(vcType)){
            kmSubsidies=vcType.getSubsidies();
            subsidy=kmSubsidies.multiply(scPriceconfMile.getCurrentValue());
        }else{
            Calendar cal = Calendar.getInstance();
            int month = cal.get(Calendar.MONTH) + 1;
            //按地区加减补贴费用
            Wrapper<DCarAllowance> locationWrapper=new EntityWrapper<>();
            locationWrapper.eq("end_province",dProvice);
            getCommonWrapper(locationWrapper, "effective_date", "invalid_date", effectDate);
            DCarAllowance location = dCarAllowanceService.selectOne(locationWrapper);
            if (Objects.nonNull(location)) {
                if (StringUtils.isBlank(location.getExcludeCity()) || !location.getExcludeCity().contains(dTag.split("-")[0])) {
                    if (location.getType() == 3 && month >= 10 || month <= 3) {
                        orderSubsidies = location.getSubsidies();
                        subsidy=orderSubsidies;
                    } else {
                        orderSubsidies = location.getSubsidies();
                        subsidy=orderSubsidies;
                    }
                }
            }
        }
        Integer fuelTypeId = dVehicleClassify.getFuelTypeId(); // 油品id
        FuelType dFuelType = fuelTypeService.selectById(fuelTypeId);
        String fuleName = dFuelType.getFuelName(); // 油品

        //里程
        BigDecimal distance = scPriceconfMile.getCurrentValue();

        //油箱容积
        BigDecimal tankVolume = scBaseCvTankvolume.getTankVolume();

        //车型油耗
        BigDecimal currentValue = scPriceconfOc.getCurrentValue();

        //劳务费单价
        BigDecimal laborCosts = scPriceconfFreight.getCurrentValue();


        //单趟所需油量y
        BigDecimal totalOil = currentValue.multiply(distance).divide(BigDecimal.valueOf(100).setScale(COMMON_INT, BigDecimal.ROUND_HALF_UP));

        //油箱最高加油量z
        BigDecimal maxOil = tankVolume.multiply(BigDecimal.valueOf(0.85));

        //第一箱油量
        BigDecimal firstBucketOil = null;

        //剩余油量
        BigDecimal remainOil = null;

        //单趟所需油量>=油箱最高加油量,第一箱油为油箱最高加油量z,剩余油量为单趟所需油量-油箱最高加油量 x-z
        if (totalOil.intValue() >= maxOil.intValue()) {
            firstBucketOil = maxOil;
            remainOil = totalOil.subtract(maxOil);
        }
        //单趟所需油量<油箱最高加油量,第一箱油为单趟所需油量y,油箱剩余油量为x-y即为0
        if (totalOil.intValue() < maxOil.intValue()) {
            firstBucketOil = totalOil;
            remainOil = totalOil.subtract(totalOil);
        }
        // 第一桶油量向下取整数
        firstBucketOil = firstBucketOil.setScale(0, BigDecimal.ROUND_DOWN);

        // 单公里油价  百公里油耗 /100 * 油价
        BigDecimal priceOilPerKm = scPriceconfOc.getCurrentValue().divide(BigDecimal.valueOf(100)).multiply(fuelPriceEffective.getMarketPrice()).setScale(COMMON_INT, BigDecimal.ROUND_HALF_UP);

        // 总劳务费 = 劳务费单价 * 里程
        // BigDecimal totalLaborCosts = laborCosts.multiply(distance).setScale(2, RoundingMode.HALF_UP);
        BigDecimal totalLaborCosts = laborCosts.multiply(distance);

        // 总油费 =  单公里油价 * 里程
        BigDecimal totalOilFee = scPriceconfOc.getCurrentValue().divide(BigDecimal.valueOf(100)).multiply(fuelPriceEffective.getMarketPrice()).multiply(distance).setScale(COMMON_INT, BigDecimal.ROUND_HALF_UP);

        // 总油量
        BigDecimal totalFuelConsumption = scPriceconfOc.getCurrentValue().divide(BigDecimal.valueOf(100)).multiply(distance).setScale(COMMON_INT, BigDecimal.ROUND_HALF_UP);

        // 第一桶油费 = 市场价 * 第一桶油量
        // BigDecimal firstBucketFee = remainOil.compareTo(new BigDecimal("0.00")) == 0 ? totalOilFee : firstBucketOil.multiply(fuelPriceEffective.getMarketPrice()).setScale(2, BigDecimal.ROUND_HALF_UP);
        BigDecimal firstBucketFee = firstBucketOil.multiply(fuelPriceEffective.getMarketPrice()).setScale(2, BigDecimal.ROUND_HALF_UP);

        // 剩余油费（充值油费） = 总油费 - 第一桶油费
        BigDecimal remainingOilFee = totalOilFee.subtract(firstBucketFee);

        //总运价 =  总劳务费 + 总油费 + 附加费；
        if (null == extraCost) {
            extraCost = new BigDecimal(0);
        }
        BigDecimal totalFreight = totalLaborCosts.add(totalOilFee).add(extraCost).setScale(2, BigDecimal.ROUND_HALF_UP);

        Map<Integer, Object> fees = new HashedMap();
        fees.put(DWaybillFeeEnum.LABOR_COSTS.getValue(), totalLaborCosts);//运费(服务费)
        fees.put(DWaybillFeeEnum.REMAINING_OIL_FEE.getValue(), remainingOilFee);//油卡充值金额
        fees.put(DWaybillFeeEnum.MARKET_OIL_PRICE.getValue(), fuelPriceEffective.getMarketPrice());//油价
        fees.put(DWaybillFeeEnum.TOTAL_OIL_COST.getValue(), totalOilFee.setScale(2, BigDecimal.ROUND_HALF_UP));//总油费
        fees.put(DWaybillFeeEnum.TOTAL_SHIPPING_COST.getValue(), totalFreight);//总运费
        fees.put(DWaybillFeeEnum.SHIP_DISTANCE.getValue(), distance);//公里数   =1 后加
        fees.put(DWaybillFeeEnum.PRICE_PER_KM.getValue(), laborCosts);//单公里运价   =2 后加
        fees.put(DWaybillFeeEnum.FIRST_BUCKET_OIL_FEE.getValue(), firstBucketFee.setScale(2, BigDecimal.ROUND_HALF_UP));//第一桶油费 = 3 后加
        fees.put(DWaybillFeeEnum.PRICE_OIL_PER_KM.getValue(), priceOilPerKm);//单公里油价 = 4 后加
        fees.put(DWaybillFeeEnum.FIRST_BUCKET_OIL.getValue(), firstBucketOil);//第一桶油量 = 5 2017-06-06 11:22:55  ligl
        fees.put(DWaybillFeeEnum.OIL_CONSUMPTION.getValue(), currentValue);//车型油耗 = 6 2017-06-06 11:22:55  ligl
        fees.put(DWaybillFeeEnum.REMAIN_OIL.getValue(), remainOil);//剩余油量 = 7 2017-06-06 11:22:55  ligl
        fees.put(DWaybillFeeEnum.TANKVOLUME.getValue(), tankVolume);//车型容积 = 8 2017-06-06 11:22:55  ligl
        fees.put(DWaybillFeeEnum.FUEL_TYPE.getValue(), fuleName);//油品 = 9 2017-06-06 11:22:55  ligl
        fees.put(DWaybillFeeEnum.TOTAL_FUEL_CONSUMPTION.getValue(), totalFuelConsumption);//总油量 = 10 2017-07-05 17:45:50  ligl
        fees.put(DWaybillFeeEnum.SUBSIDY.getValue(), subsidy);//  补贴 = 10 2017-07-05 17:45:50  ligl
        return fees;
    }

    private void getCommonWrapper(Wrapper wrapper, String startColum, String endColum, Date effectDate) {
        wrapper.le(startColum, effectDate);
        wrapper.andNew().isNull(endColum).or().gt("invalid_date", effectDate);
    }

    private FuelPriceEffective selectCurrentOilPrice(Integer fuelTypeId, Date effectDate) {
        if (null == fuelTypeId) {
            log.error("CalcDriverCostImpl.selectCurrentOilPrice param fuelTypeId must not be null");
            throw new IllegalArgumentException("燃油类型主键不能为空");
        }

        //查询市场油价
        Wrapper ewPriceconfFreight = new EntityWrapper();
        ewPriceconfFreight.eq("fuel_type_id", fuelTypeId);
        ewPriceconfFreight.le("effective_date", effectDate);
        ewPriceconfFreight.isNull("invalid_date");
        FuelPriceEffective fuelPriceEffective = fuelPriceEffectiveService.selectOne(ewPriceconfFreight);

        if (Objects.isNull(fuelPriceEffective)) {
            ewPriceconfFreight = new EntityWrapper();
            ewPriceconfFreight.eq("fuel_type_id", fuelTypeId);
            ewPriceconfFreight.le("effective_date", effectDate);
            ewPriceconfFreight.gt("invalid_date", effectDate);
            fuelPriceEffective = fuelPriceEffectiveService.selectOne(ewPriceconfFreight);
        }
        if (Objects.isNull(fuelPriceEffective)) {
            log.error("CalcDriverCostImpl.selectCurrentOilPrice error feeEffectives is empty");
            throw new BaseException("燃油价格变动不能为空");
        }
        return fuelPriceEffective;
    }

    @Override
    public Map<Integer, Object> getScMap(String vehicleClassifyId) throws Exception {
        /**
         * 查询车型分类
         */
        Wrapper ewVehicel = new EntityWrapper();
        ewVehicel.eq("vehicle_classify_id", vehicleClassifyId);
        VehicleClassify dVehicleClassify = vehicleClassifyService.selectOne(ewVehicel);
        if (null == dVehicleClassify) {
            log.error("DWaybillFeeServiceImpl.getWaybillFirstBucketOil dVehicleClassifies dVehicleClassify must not be null");
            throw new BaseException("车型分类不能为空");
        }

        /**
         * 查询车型油耗
         */
        Wrapper ewPriceconfOc = new EntityWrapper();
        ewPriceconfOc.eq("vehicle_type_id", dVehicleClassify.getId());
        ewPriceconfOc.le("effective_date", new Date());
        ewPriceconfOc.isNull("invalid_date");
        PriceconfOc scPriceconfOc = priceconfOcService.selectOne(ewPriceconfOc);
        if (null == scPriceconfOc) {
            log.error("CalcDriverCostImpl.getWaybillCostByCalc scPriceconfOcs must not be null");
            throw new BaseException("车型油耗不能为空");
        }

        /**
         * 查询油箱容积
         */
        Wrapper ewCvTank = new EntityWrapper();
        ewCvTank.eq("cv_type_id", vehicleClassifyId);
        BaseCvTankvolume scBaseCvTankvolume = baseCvTankvolumeService.selectOne(ewCvTank);
        if (null == scBaseCvTankvolume) {
            log.error("CalcDriverCostImpl.getWaybillCostByCalc scBaseCvTankvolume must not be null");
            throw new BaseException("油箱容积不能为空");
        }

        Integer fuelTypeId = dVehicleClassify.getFuelTypeId(); // 油品id
        FuelType dFuelType = fuelTypeService.selectById(fuelTypeId);
        String fuleName = dFuelType.getFuelName(); // 油品

        Map<Integer, Object> fees = new HashedMap();
        fees.put(DWaybillFeeEnum.OIL_CONSUMPTION.getValue(), scPriceconfOc.getCurrentValue());//车型油耗 = 6 2017-06-06 11:22:55  ligl
        fees.put(DWaybillFeeEnum.TANKVOLUME.getValue(), scBaseCvTankvolume.getTankVolume());//车型容积 = 8 2017-06-06 11:22:55  ligl
        fees.put(DWaybillFeeEnum.FUEL_TYPE.getValue(), fuleName);//油品 = 9 2017-06-06 11:22:55  ligl

        return fees;

    }
}
